67beebf859e2078c014a203e3285f64958fb3299,router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java,HandleDatabaseLookupMessageJob,runJob,#,60

Before Change



        // TODO only look up once, then check type
        LeaseSet ls = getContext().netDb().lookupLeaseSetLocally(_message.getSearchKey());
        if (ls != null) {
            // We have to be very careful here to decide whether or not to send out the leaseSet,
            // to avoid anonymity vulnerabilities.
            // As this is complex, lots of comments follow...

            boolean isLocal = getContext().clientManager().isLocal(ls.getDestination());
            boolean shouldPublishLocal = isLocal && getContext().clientManager().shouldPublishLeaseSet(_message.getSearchKey());
        
            // Only answer a request for a LeaseSet if it has been published
            // to us, or, if its local, if we would have published to ourselves

            // answerAllQueries: We are floodfill
            // getReceivedAsPublished:
            //    false for local
            //    false for received over a tunnel
            //    false for received in response to our lookups
            //    true for received in a DatabaseStoreMessage unsolicited
            if (ls.getReceivedAsPublished()) {
                // Answer anything that was stored to us directly
                // (i.e. "received as published" - not the result of a query, or received
                // over a client tunnel).
                // This is probably because we are floodfill, but also perhaps we used to be floodfill,
                // so we don't check the answerAllQueries() flag.
                // Local leasesets are not handled here
                if (_log.shouldLog(Log.INFO))
                    _log.info("We have the published LS " + _message.getSearchKey().toBase64() + ", answering query");
                getContext().statManager().addRateData("netDb.lookupsMatchedReceivedPublished", 1, 0);
                sendData(_message.getSearchKey(), ls, fromKey, _message.getReplyTunnel());
            } else if (shouldPublishLocal && answerAllQueries()) {
                // We are floodfill, and this is our local leaseset, and we publish it.
                // Only send it out if it is in our estimated keyspace.
                // For this, we do NOT use their dontInclude list as it can't be trusted
                // (i.e. it could mess up the closeness calculation)
                Set<Hash> closestHashes = getContext().netDb().findNearestRouters(_message.getSearchKey(), 
                                                                            CLOSENESS_THRESHOLD, null);
                if (weAreClosest(closestHashes)) {
                    // It's in our keyspace, so give it to them
                    if (_log.shouldLog(Log.INFO))
                        _log.info("We have local LS " + _message.getSearchKey().toBase64() + ", answering query, in our keyspace");
                    getContext().statManager().addRateData("netDb.lookupsMatchedLocalClosest", 1, 0);
                    sendData(_message.getSearchKey(), ls, fromKey, _message.getReplyTunnel());
                } else {
                    // Lie, pretend we don't have it
                    if (_log.shouldLog(Log.INFO))
                        _log.info("We have local LS " + _message.getSearchKey().toBase64() + ", NOT answering query, out of our keyspace");
                    getContext().statManager().addRateData("netDb.lookupsMatchedLocalNotClosest", 1, 0);
                    Set<Hash> routerHashSet = getNearestRouters();
                    sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
                }
            } else {
                // It was not published to us (we looked it up, for example)
                // or it's local and we aren't floodfill,
                // or it's local and we don't publish it.
                // Lie, pretend we don't have it
                if (_log.shouldLog(Log.INFO))
                    _log.info("We have LS " + _message.getSearchKey().toBase64() +
                               ", NOT answering query - local? " + isLocal + " shouldPublish? " + shouldPublishLocal +
                               " RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
                getContext().statManager().addRateData("netDb.lookupsMatchedRemoteNotClosest", 1, 0);
                Set<Hash> routerHashSet = getNearestRouters();
                sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
            }
        } else {
            RouterInfo info = getContext().netDb().lookupRouterInfoLocally(_message.getSearchKey());
            if ( (info != null) && (info.isCurrent(EXPIRE_DELAY)) ) {
                if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) {
                    if (_log.shouldLog(Log.DEBUG))
                        _log.debug("Not answering a query for a netDb peer who isn't reachable");
                    Set<Hash> us = new HashSet<Hash>(1);
                    us.add(getContext().routerHash());
                    sendClosest(_message.getSearchKey(), us, fromKey, _message.getReplyTunnel());
                //} else if (info.isHidden()) {
                //    // Don't return hidden nodes
                //    ERR: we don't want to explicitly reject lookups for hidden nodes, since they
                //         may have just sent the hidden mode to only us and bundled a lookup with
                //         a payload targetting some hidden destination (and if we refused to answer,
                //         yet answered the bundled data message [e.g. HTTP GET], they'd know that
                //         *we* were hosting that destination).  To operate safely,
                //         perhaps we should refuse to honor lookups bundled down client tunnels?
                } else {
                    // send that routerInfo to the _message.getFromHash peer
                    if (_log.shouldLog(Log.DEBUG))
                        _log.debug("We do have key " + _message.getSearchKey().toBase64() 
                                   + " locally as a router info.  sending to " + fromKey.toBase64());
                    sendData(_message.getSearchKey(), info, fromKey, _message.getReplyTunnel());
                }
            } else {

After Change



        // only lookup once, then cast to correct type
        DatabaseEntry dbe = getContext().netDb().lookupLocally(_message.getSearchKey());
        if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_LEASESET) {
            LeaseSet ls = (LeaseSet) dbe;
            // We have to be very careful here to decide whether or not to send out the leaseSet,
            // to avoid anonymity vulnerabilities.
            // As this is complex, lots of comments follow...

            boolean isLocal = getContext().clientManager().isLocal(ls.getDestination());
            boolean shouldPublishLocal = isLocal && getContext().clientManager().shouldPublishLeaseSet(_message.getSearchKey());
        
            // Only answer a request for a LeaseSet if it has been published
            // to us, or, if its local, if we would have published to ourselves

            // answerAllQueries: We are floodfill
            // getReceivedAsPublished:
            //    false for local
            //    false for received over a tunnel
            //    false for received in response to our lookups
            //    true for received in a DatabaseStoreMessage unsolicited
            if (ls.getReceivedAsPublished()) {
                // Answer anything that was stored to us directly
                // (i.e. "received as published" - not the result of a query, or received
                // over a client tunnel).
                // This is probably because we are floodfill, but also perhaps we used to be floodfill,
                // so we don't check the answerAllQueries() flag.
                // Local leasesets are not handled here
                if (_log.shouldLog(Log.INFO))
                    _log.info("We have the published LS " + _message.getSearchKey() + ", answering query");
                getContext().statManager().addRateData("netDb.lookupsMatchedReceivedPublished", 1, 0);
                sendData(_message.getSearchKey(), ls, fromKey, _message.getReplyTunnel());
            } else if (shouldPublishLocal && answerAllQueries()) {
                // We are floodfill, and this is our local leaseset, and we publish it.
                // Only send it out if it is in our estimated keyspace.
                // For this, we do NOT use their dontInclude list as it can't be trusted
                // (i.e. it could mess up the closeness calculation)
                Set<Hash> closestHashes = getContext().netDb().findNearestRouters(_message.getSearchKey(), 
                                                                            CLOSENESS_THRESHOLD, null);
                if (weAreClosest(closestHashes)) {
                    // It's in our keyspace, so give it to them
                    if (_log.shouldLog(Log.INFO))
                        _log.info("We have local LS " + _message.getSearchKey() + ", answering query, in our keyspace");
                    getContext().statManager().addRateData("netDb.lookupsMatchedLocalClosest", 1, 0);
                    sendData(_message.getSearchKey(), ls, fromKey, _message.getReplyTunnel());
                } else {
                    // Lie, pretend we don't have it
                    if (_log.shouldLog(Log.INFO))
                        _log.info("We have local LS " + _message.getSearchKey() + ", NOT answering query, out of our keyspace");
                    getContext().statManager().addRateData("netDb.lookupsMatchedLocalNotClosest", 1, 0);
                    Set<Hash> routerHashSet = getNearestRouters();
                    sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
                }
            } else {
                // It was not published to us (we looked it up, for example)
                // or it's local and we aren't floodfill,
                // or it's local and we don't publish it.
                // Lie, pretend we don't have it
                if (_log.shouldLog(Log.INFO))
                    _log.info("We have LS " + _message.getSearchKey() +
                               ", NOT answering query - local? " + isLocal + " shouldPublish? " + shouldPublishLocal +
                               " RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
                getContext().statManager().addRateData("netDb.lookupsMatchedRemoteNotClosest", 1, 0);
                Set<Hash> routerHashSet = getNearestRouters();
                sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
            }
        } else if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
            RouterInfo info = (RouterInfo) dbe;
            if (info.isCurrent(EXPIRE_DELAY)) {
                if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) {